import logging
import datetime

from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from google.appengine.api import users
from google.appengine.ext import db

from GAE.guestbook.models import TermStructure, WebCrawler
from GAE.guestbook.decorators import auth_required
from GAE.lib.gaesessions import get_current_session
from GAE.lib.urlwatch.handler import UrlJob


def _get_date_from_post(date, post_data):
    """
    Retrieves and converts the date from the post data, it either uses the one
    submitted date or the component parts on month, day, year.

    Arguments:
        1. date - a string representing the date's key in the post
        2. post_data - the post data to get the date from.

    Returns:
        datetime.date object of the date in the post.

    Exceptions:
        KeyError if certain keys in POST data do not exist.
        ValueError from datetime.datetime.strptime if conversion fails.
    """
    # If we have the date_month variable in the POST, then we will assume the
    # user hit the application with the javascript feature off. In this case we
    # will build the date to validate from the string components.

    logging.debug("Found '%s' from form with JavaScript disabled." % date)
    # OK, then lets start to set the date as a string for validation.
    # Essentially just changing the component to be a validated date
    # string and turned into a date.
    format_string = '/'.join(["{{0[{0}_month]}}", "{{0[{0}_day]}}",
            "{{0[{0}_year]}}"]).format(date)
    formatted_date = format_string.format(post_data)
    return datetime.datetime.strptime(formatted_date, "%m/%d/%Y").date()


def get_common_data_dict(request):
    '''
    Populate the common data dictionary and return the dictionary.
    '''

    common_data_dict = dict()

    common_data_dict["show_login_info"] = True
    common_data_dict["login_url"] = users.create_login_url(request.path)
    common_data_dict["logout_url"] = users.create_logout_url(request.path)
    common_data_dict["profile_url"] = reverse(profile)
    common_data_dict["support_url"] = reverse(support)

    # Find out if the user is saved in the database
    query = db.GqlQuery("SELECT * FROM Account where login= :1",
                        users.get_current_user())
    common_data_dict["user"] = \
        get_current_session()["user"] = \
            query.get()

    return common_data_dict


def main(request):
    '''
    Index page for the app
    '''

    data_dictionary = dict()

    # Get the common data dictionary
    data_dictionary.update(get_common_data_dict(request))

    if request.method =="POST":
        return HttpResponseRedirect(reverse(manage_item))

    return render_to_response("main.html", data_dictionary)


@auth_required
def set_monitor(request):
    '''
    Set the criteria to monitor VIX term structure
    '''

    data_dictionary = dict()
    
    # Get the common data dictionary
    data_dictionary.update(get_common_data_dict(request))

    # Get the session
    session = get_current_session()

    # Get the account for the current user
    current_user = request.session.get("user")

    # Clear the validation error dict
    session["validation_errors"] = dict()

    # Get the watch item by id
    term_structure_obj = None

    # Retrieve the term structure if the url is visited.
    if TermStructure.all().count() > 0:
        query = TermStructure.all()
        query.filter("account =", current_user)
        term_structure_obj = query.get()
        logging.info("Retrieved a term schedule %s" % term_structure_obj)

    # Pass the term structure to the template
    if term_structure_obj:
        data_dictionary["term_structure"] = \
            request.session["term_structure"] = term_structure_obj
        logging.info(
            "Passing a term structure to update for user, %s to template",
            term_structure_obj.account.login)

    if request.method =="POST":
        # Get the user inputs
        slope = request.POST.get('slope','').strip()
        email_enabled = request.POST.get('email_enabled','').strip()

        # Make sure the login is not blank
        if not slope:
            logging.error("Slope field is empty.")
            request.session["validation_errors"].\
                    update({"slope_missing": True})

        # Check if the slope value is (not) a float type
        try:
            # We will save the value in percentile
            # i.e. slope 5 is actually 0.05
            slope_float = float(slope)

            logging.info("Slope = %s%%" % slope_float)
        except ValueError as ex:
            logging.error(ex)
            logging.error("Slope value is not a valid float number.")
            request.session["validation_errors"].\
                   update({"slope_invalid": True})


        # email_enabled from the template should be empty if it is
        # unchecked.
        email_enabled_bool = bool(email_enabled)

        logging.info("Email Enabled = %s" % email_enabled_bool)

        # Check if a validation error exists.
        if session["validation_errors"]:
            data_dictionary.update(session["validation_errors"])
            return render_to_response("set_monitor.html", data_dictionary)

        # Add or edit a term structure
        try:
            # Pass the watch item to the template
            if term_structure_obj:
                logging.info("Updating a term structure: %s" %
                             term_structure_obj)
                term_structure_obj.slope = slope_float
                term_structure_obj.email_enabled = email_enabled_bool

            # Add the new watch item
            else:
                logging.info("Adding a new term structure")
                term_structure_obj = \
                    TermStructure(slope=slope_float,
                                  email_enabled=email_enabled_bool,
                                  account=current_user)
            term_structure_obj.put()

            data_dictionary["update_successful"] = True

            logging.info("update successful was set true")

            # return HttpResponseRedirect(reverse(set_monitor))

        except Exception as ex:
            logging.error("Failed to add or edit a term structure: %s", ex)
            data_dictionary.update(session["validation_errors"])

            request.session["update_successful"] = False

            return HttpResponseRedirect(reverse(app_fail))

    return render_to_response("set_monitor.html", data_dictionary)



def monitor_vix_data(request):
    '''
    Fetch and store the vix quote data to the database
    '''

    # TODO: Decide if we want to store the VIX quotes
    # Now fetch the new vix quote

    WebCrawler(settings.VIX_SITE).monitor_vix_data()

    # Update the posting data
    return HttpResponse("Fetching the vix quote is done.")


def app_fail(request):
    '''
    Destination if the error can't recover from the user input.
    '''

    data_dictionary = dict()

    # Get the common data dictionary
    data_dictionary.update(get_common_data_dict(request))

    return render_to_response("app_fail.html", data_dictionary)


def support(request):
    '''
    Support page for the app
    '''

    data_dictionary = dict()

    # Get the common data dictionary
    data_dictionary.update(get_common_data_dict(request))

    return render_to_response("support.html", data_dictionary)


@auth_required
def profile(request):
    '''
    Profile view
    '''

    data_dictionary = dict()

    # Get the common data dictionary
    data_dictionary.update(get_common_data_dict(request))

    # Get the session
    session = get_current_session()

    # Clear the validation error dict
    session["validation_errors"] = dict()

    if request.method =="POST":
        # Get the user inputs
        email = request.POST.get('email', '').strip()
        account = request.session.get("user")

        # Make sure the email is not blank.
        if not email:
            logging.info("Primary email was empty.")
            session["validation_errors"].update({"email_missing": True})
            data_dictionary.update(session["validation_errors"])
            return render_to_response("profile.html", data_dictionary)

        account.first_name = request.POST.get('first_name', '').strip()
        account.last_name = request.POST.get('last_name', '').strip()
        account.primary_email = request.POST.get('email', '').strip()
        account.put()

        data_dictionary["update_success"] = True


    return render_to_response("profile.html", data_dictionary)